package com.ling.pl.security.decision;

import com.ling.pl.core.commons.utils.PropertiesUtils;
import com.ling.pl.security.model.DefaultOrg;
import com.ling.pl.security.model.DefaultUser;
import com.ling.pl.security.utils.AttributeType;
import com.ling.pl.security.utils.ConfigAttribute;
import com.ling.pl.security.utils.SecurityConfigAttribute;

import java.util.Collection;
import java.util.List;

/**
 * @author bo.wang
 */
public abstract class AbstractAccessDecisionVoter implements AccessDecisionVoter {

    public int vote111(DefaultUser authentication, List attributes) {
        return ACCESS_DENIED;
    }

    public boolean supports(SecurityConfigAttribute attribute) {
        if (!(attribute instanceof SecurityConfigAttribute)) {
            return false;
        }
        SecurityConfigAttribute securityConfigAttribute = (SecurityConfigAttribute) attribute;
        if (securityConfigAttribute.getAttributeType().equals(getAttributeType())) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 先判断当前给出的部门当中有没有允许或拒绝访问的部门，如果有直接返回，<br>
     * 如果没有同时又允许继承父部门权限，那么就对给出部门的上级部门进行判断，如果有返回，否则继续以递归形式向上级部门查找
     *
     * @param attributes 权限资源信息
     * @param orgs       要评测的部门集合
     * @return 评测的结果
     */
    protected int decitionOrgs(Collection<ConfigAttribute> attributes, List<DefaultOrg> orgs) {
        int voteResult = ACCESS_ABSTAIN;
        for (DefaultOrg org : orgs) {
            voteResult = voteOrg(attributes, org);
            if (voteResult != ACCESS_ABSTAIN) {
                return voteResult;
            }
        }
        boolean inheriteParentOrgPermission = PropertiesUtils.getBoolean("ling2.inheritParentOrgPermission");
        if (!inheriteParentOrgPermission) {
            return voteResult;
        }
        for (DefaultOrg org : orgs) {
            if (org.getParent() == null) {
                continue;
            }
            voteResult = recurVoteParentOrg(attributes, org.getParent());
            if (voteResult != ACCESS_ABSTAIN) {
                break;
            }
        }
        return voteResult;
    }

    private int recurVoteParentOrg(Collection<ConfigAttribute> attributes, DefaultOrg userOrg) {
        int voteResult = voteOrg(attributes, userOrg);
        if (voteResult == ACCESS_ABSTAIN && userOrg.getParent() != null) {
            voteResult = recurVoteParentOrg(attributes, userOrg.getParent());
        }
        return voteResult;
    }

    private int voteOrg(Collection<ConfigAttribute> attributes, DefaultOrg userOrg) {
        for (ConfigAttribute attribute : attributes) {
            SecurityConfigAttribute configAttribute = (SecurityConfigAttribute) attribute;
            if (!configAttribute.getAttributeType().equals(AttributeType.org)) {
                continue;
            }
            boolean granted = configAttribute.isGranted();
            DefaultOrg org = (DefaultOrg) configAttribute.getMember();
            if (org.getId().equals(userOrg.getId())) {
                if (granted) {
                    return ACCESS_GRANTED;
                } else {
                    return ACCESS_DENIED;
                }
            }
        }
        return ACCESS_ABSTAIN;
    }

    public boolean supports(Class<?> clazz) {
        return true;
    }

    protected abstract AttributeType getAttributeType();
}
